/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "imageknife_test.h"
#include "imageknife_internal.h"
#include "napi_parser.h"
#include "option/imageknife_option_napi.h"
#include "interceptor/file_cache_interceptor_default.h"
#include "log.h"
#include "task_worker.h"

namespace ImageKnifeTest {

static std::atomic<bool> g_executingPackFile = false;

napi_value ImageKnifeGetPreCreatedNodeCount(napi_env env, napi_callback_info info)
{
    napi_value result;
    auto &imageKnifeInternal = ImageKnifePro::ImageKnifeInternal::GetInstance();
    napi_create_int32(env, imageKnifeInternal.GetPreCreatedNodeCout(), &result);
    return result;
}

napi_value RemoveFileAsyncCallbackVersion(napi_env env, napi_callback_info info)
{
    napi_value optionValue;
    size_t argc = 1;
    napi_get_cb_info(env, info, &argc, &optionValue, nullptr, nullptr);
    auto imageKnifeOption = std::make_shared<ImageKnifePro::ImageKnifeOptionNapi>(env, optionValue);

    // 构造js的promise
    napi_value promise;
    napi_deferred deferred;
    napi_create_promise(env, &deferred, &promise);

    auto callback = [env, deferred]() {
        // 空入参使用undefined 进行Resolve
        napi_value undefined;
        napi_get_undefined(env, &undefined);
        napi_resolve_deferred(env, deferred, undefined);
    };

    // 调用带回调的版本，回调确保在主线程触发
    ImageKnifePro::ImageKnife::GetInstance().RemoveFileAsync(imageKnifeOption, callback);
    return promise;
}

napi_value RemoveAllFileAsyncCallbackVersion(napi_env env, napi_callback_info info)
{
    const size_t argCount = 1;
    size_t argc = argCount;
    napi_value args[argCount] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string cacheName = ImageKnifePro::NapiParser::ParseString(env, args[0]);

    // 构造js的promise
    napi_value promise;
    napi_deferred deferred;
    napi_create_promise(env, &deferred, &promise);

    auto callback = [env, deferred]() {
        // 空入参使用undefined 进行Resolve
        napi_value undefined;
        napi_get_undefined(env, &undefined);
        napi_resolve_deferred(env, deferred, undefined);
    };

    // 调用带回调的版本，回调确保在主线程触发
    ImageKnifePro::ImageKnife::GetInstance().RemoveAllFileAsync(callback, cacheName);
    return promise;
}

napi_value PreloadCacheCallbackVersion(napi_env env, napi_callback_info info)
{
    const size_t argCount = 1;
    size_t argc = argCount;
    napi_value args[argCount] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    auto imageKnifeOption = std::make_shared<ImageKnifePro::ImageKnifeOptionNapi>(env, args[0]);

    // 构造js的promise
    napi_value promise;
    napi_deferred deferred;
    napi_create_promise(env, &deferred, &promise);

    auto callback = [env, deferred](std::string filePath) {
        napi_value strValue;
        napi_create_string_utf8(env, filePath.c_str(), NAPI_AUTO_LENGTH, &strValue);
        napi_resolve_deferred(env, deferred, strValue);
    };

    // 调用带回调的版本，回调确保在主线程触发
    ImageKnifePro::ImageKnife::GetInstance().PreloadCache(imageKnifeOption, callback);
    return promise;
}

void ResolveImageData(napi_env env, napi_deferred deferred, std::shared_ptr<ImageKnifePro::ImageData> imageData)
{
    using namespace ImageKnifePro;
    if (imageData == nullptr) {
        IMAGE_KNIFE_LOG(LOG_ERROR, "PromiseNapi:: imageData == nullptr");
        napi_value undefined;
        napi_get_undefined(env, &undefined);
        napi_resolve_deferred(env, deferred, undefined);
        return;
    }

    napi_value jsImageData;
    napi_create_object(env, &jsImageData);

    int frameCount = imageData->GetFrameCount();
    napi_value value;
    napi_create_int32(env, frameCount, &value);
    napi_set_named_property(env, jsImageData, "frameCount", value);

    OH_PixelmapNative **pixelmapList = imageData->GetPixelmapList();
    if (pixelmapList != nullptr) {
        napi_value pixelmapListValue;
        napi_create_array_with_length(env, frameCount, &pixelmapListValue);
        for (int i = 0; i < frameCount; i++) {
            napi_value pixelmap;
            OH_PixelmapNative_ConvertPixelmapNativeToNapi(env, pixelmapList[i], &pixelmap);
            napi_set_element(env, pixelmapListValue, i, pixelmap);
        }
        napi_set_named_property(env, jsImageData, "pixelmapList", pixelmapListValue);
    }

    int *delayTimeList = imageData->GetDelayTimeList();
    if (delayTimeList != nullptr) {
        napi_value timeList;
        napi_create_array_with_length(env, frameCount, &timeList);
        for (int i = 0; i < frameCount; i++) {
            napi_value number;
            napi_create_int32(env, delayTimeList[i], &number);
            napi_set_element(env, timeList, i, number);
        }
        napi_set_named_property(env, jsImageData, "delayTimeList", timeList);
    }

    napi_resolve_deferred(env, deferred, jsImageData);
}

napi_value GetCacheImageCallbackVersion(napi_env env, napi_callback_info info)
{
    const size_t argCount = 2;
    size_t argc = argCount;
    napi_value args[argCount] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    auto imageKnifeOption = std::make_shared<ImageKnifePro::ImageKnifeOptionNapi>(env, args[0]);
    auto cacheStrategy = static_cast<ImageKnifePro::CacheStrategy>(ImageKnifePro::NapiParser::ParseInt(env, args[1]));

    // 构造js的promise
    napi_value promise;
    napi_deferred deferred;
    napi_create_promise(env, &deferred, &promise);

    auto callback = [env, deferred](std::shared_ptr<ImageKnifePro::ImageData> imageData) {
        ResolveImageData(env, deferred, imageData);
    };

    // 调用带回调的版本，回调确保在主线程触发
    ImageKnifePro::ImageKnife::GetInstance().GetCacheImage(imageKnifeOption, callback, cacheStrategy);
    return promise;
}

napi_value GetCacheImageSyncBlock(napi_env env, napi_callback_info info)
{
    const size_t argCount = 1;
    size_t argc = argCount;
    napi_value args[argCount] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    auto imageKnifeOption = std::make_shared<ImageKnifePro::ImageKnifeOptionNapi>(env, args[0]);

    auto future = ImageKnifePro::ImageKnife::GetInstance().GetCacheImage(imageKnifeOption);
    // 测试阻塞主线程
    future.get();
    return nullptr;
}

napi_value PreloadCacheSyncBlock(napi_env env, napi_callback_info info)
{
    const size_t argCount = 1;
    size_t argc = argCount;
    napi_value args[argCount] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    auto imageKnifeOption = std::make_shared<ImageKnifePro::ImageKnifeOptionNapi>(env, args[0]);

    auto future = ImageKnifePro::ImageKnife::GetInstance().PreloadCache(imageKnifeOption);
    // 测试阻塞主线程
    future.get();
    return nullptr;
}

napi_value ImageResizeTo8kAndSaveFileCache(napi_env env, napi_callback_info info)
{
    using namespace ImageKnifePro;
    const size_t argCount = 2;
    size_t argc = argCount;
    napi_value args[argCount] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    auto imageKnifeOption = std::make_shared<ImageKnifeOptionNapi>(env, args[0]);
    std::string key = NapiParser::ParseString(env, args[1]);

    // 构造js的promise
    napi_value promise;
    napi_deferred deferred;
    napi_create_promise(env, &deferred, &promise);
    auto callback = [env, deferred, key](std::shared_ptr<ImageData> imageData) {
        // 子线程写20张4k的图片至文件缓存
        auto execute = [imageData, key](void *) {
            if (imageData == nullptr) {
                return;
            }

            if (g_executingPackFile) {
                IMAGE_KNIFE_LOG(LOG_DEBUG, "PackFile Executing");
                return;
            }
            g_executingPackFile = true;
            auto pixelmap = imageData->GetPixelmap();
            IMAGE_KNIFE_CHECK(pixelmap == nullptr);
            auto imageSize = PixelmapUtils::GetImageSize(pixelmap);
            IMAGE_KNIFE_CHECK(imageSize.height == 0 || imageSize.width == 0);
            const size_t height_8k = 4300;
            const size_t width_8k = 7600;

            OH_PixelmapNative_Scale(pixelmap, width_8k / static_cast<float>(imageSize.width),
                                    height_8k / static_cast<float>(imageSize.height));
            const size_t loop = 20;
            for (int i = 0; i < loop; i++) {
                ImageSource imgSource;
                imgSource.SetString(key + std::to_string(i));
                auto fileName = ImageKnifeInternal::GetInstance().GetCacheKeyGenerator()->GenerateFileKey(&imgSource);
                FileCacheInterceptorDefault::GetInstance()->PackPixelmapToFile(fileName, pixelmap, "");
                IMAGE_KNIFE_LOG(LOG_DEBUG, "Pack File: %{public}s%{public}d", key.c_str(), i);
            }
            g_executingPackFile = false;
        };
        // 主线程Resolve promise
        auto complete = [env, deferred](void *) {
            napi_value undefined;
            napi_get_undefined(env, &undefined);
            napi_resolve_deferred(env, deferred, undefined);
        };
        TaskWorker::GetInstance()->PushTask(execute, complete, nullptr);
    };

    ImageKnifePro::ImageKnife::GetInstance().GetCacheImage(imageKnifeOption, callback);
    return promise;
}

napi_value Write1kUselessFileCache(napi_env env, napi_callback_info info)
{
    auto func = [](void *) {
        const size_t fileCount = 1000;
        std::string fileContent = "Test File Content";

        auto option = std::make_shared<ImageKnifePro::ImageKnifeOption>();
        auto request = std::make_shared<ImageKnifePro::ImageKnifeRequestInternal>(option);
        auto task = std::make_shared<ImageKnifePro::ImageKnifeTaskInternal>(ImageKnifePro::ImageRequestType::MAIN_SRC,
            request, nullptr);
        task->product.imageBuffer = std::shared_ptr<uint8_t []>(reinterpret_cast<uint8_t *>(&fileContent[0]),
                                                                [](void *) {});
        task->product.imageLength = fileContent.size();
        task->cacheTask.type = ImageKnifePro::CacheTaskType::WRITE;
        for (int i = 0; i < fileCount; i++) {
            static int index = 0;
            index++;
            task->cacheTask.cacheKey = "TestFile" + std::to_string(index);
            ImageKnifePro::FileCacheInterceptorDefault::GetInstance()->Resolve(task);
        }
    };

    ImageKnifePro::TaskWorker::GetInstance()->PushTask(func, nullptr, nullptr);
    return nullptr;
}

napi_value ImageKnifeInterfaces(napi_env env, napi_value &exports)
{
    napi_property_descriptor desc[] = {
        {"imageKnifeGetPreCreatedNodeCount", nullptr, ImageKnifeGetPreCreatedNodeCount,
            nullptr, nullptr, nullptr, napi_default, nullptr},
        {"removeFileAsyncCallbackVersion", nullptr, RemoveFileAsyncCallbackVersion,
            nullptr, nullptr, nullptr, napi_default, nullptr},
        {"removeAllFileAsyncCallbackVersion", nullptr, RemoveAllFileAsyncCallbackVersion,
            nullptr, nullptr, nullptr, napi_default, nullptr},
        {"preloadCacheCallbackVersion", nullptr, PreloadCacheCallbackVersion,
            nullptr, nullptr, nullptr, napi_default, nullptr},
        {"getCacheImageCallbackVersion", nullptr, GetCacheImageCallbackVersion,
            nullptr, nullptr, nullptr, napi_default, nullptr},
        {"getCacheImageSyncBlock", nullptr, GetCacheImageSyncBlock,
            nullptr, nullptr, nullptr, napi_default, nullptr},
        {"preloadCacheSyncBlock", nullptr, PreloadCacheSyncBlock,
            nullptr, nullptr, nullptr, napi_default, nullptr},
        {"imageResizeTo8kAndSaveFileCache", nullptr, ImageResizeTo8kAndSaveFileCache,
            nullptr, nullptr, nullptr, napi_default, nullptr},
        {"write1kUselessFileCache", nullptr, Write1kUselessFileCache,
            nullptr, nullptr, nullptr, napi_default, nullptr},
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
}